﻿namespace AMS.Services.Impl;

public class FreeAssetsRepoService : IFreeAssetsRepoService
{
    private readonly DbContext _context;

    public FreeAssetsRepoService(DbContext context)
    {
        _context = context;
    }

    public async Task<PageResult<FreeAssetsRepo.QueryModel>> GetPageAsync(FreeAssetsRepo.ConditionSelectorCondition condition, CancellationToken cancellationToken)
    {
        var result = new PageResult<FreeAssetsRepo.QueryModel>();

        try
        {
            var expression = GetConditionSelectorCondition(condition);

            var freeAssetsRepos = await _context.Set<FreeAssetsRepo>()
                .Include(x => x.Assets).ThenInclude(x => x.Category)
                .Include(x => x.Assets).ThenInclude(x => x.Supplier)
                .Where(expression)
                .OrderBy(x => x.Id)
                .Skip((condition.PageNum - 1) * condition.PageSize)
                .Take(condition.PageSize)
                .AsNoTracking()
                .ToListAsync(cancellationToken);

            result.Data = freeAssetsRepos.Select(x => GetQueryModel(x));

            result.PageNum = condition.PageNum;

            result.PageSize = condition.PageSize;

            result.Total = await _context.Set<FreeAssetsRepo>().CountAsync(expression, cancellationToken);

            result.Status = OperationalResult.SUCCESS;
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    public async Task<ListResult<FreeAssetsRepo.QueryModel>> GetApprovedAsync(CancellationToken cancellationToken)
    {
        var result = new ListResult<FreeAssetsRepo.QueryModel>();

        try
        {
            var data = await _context.Set<FreeAssetsRepo>()
                .Include(x => x.Assets).ThenInclude(x => x.Category)
                .Include(x => x.Assets).ThenInclude(x => x.Supplier)
                .Where(n => n.Status == AssetsStatus.Normal && n.Stock > 0)
                .AsNoTracking()
                .ToListAsync(cancellationToken);

            result.Data = data.Select(x => GetQueryModel(x));

            result.Status = OperationalResult.SUCCESS;
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    private static FreeAssetsRepo.QueryModel GetQueryModel(FreeAssetsRepo freeAssetsRepo)
    {
        return new FreeAssetsRepo.QueryModel
        {
            Id = freeAssetsRepo.Id,
            CreatedDate = freeAssetsRepo.CreatedDate,
            LastModifiedDate = freeAssetsRepo.LastModifiedDate,
            Assets = FreeAssetsService.GetQueryModel(freeAssetsRepo.Assets),
            Stock = freeAssetsRepo.Stock,
            Status = freeAssetsRepo.Status,
        };
    }

    private static Expression<Func<FreeAssetsRepo, bool>> GetConditionSelectorCondition(FreeAssetsRepo.ConditionSelectorCondition condition)
    {
        Expression<Func<FreeAssetsRepo, bool>>? expression = null;

        if (condition.Keywords is not null)
        {
            Expression<Func<FreeAssetsRepo, bool>>? keywords = null;
            keywords = freeAssetsRepo => freeAssetsRepo.Assets.Name.Contains(condition.Keywords);
            keywords = keywords.Or(freeAssetsRepo => freeAssetsRepo.Assets.Supplier.Name.Contains(condition.Keywords));
            keywords = keywords.Or(freeAssetsRepo => freeAssetsRepo.Assets.Batch.Contains(condition.Keywords));
            expression = expression?.And(keywords) ?? keywords;
        }

        if (condition.StatusSelector is not null)
        {
            Expression<Func<FreeAssetsRepo, bool>>? statusSelector = null;
            statusSelector = freeAssetsRepo => condition.StatusSelector == freeAssetsRepo.Status;
            expression = expression?.And(statusSelector) ?? statusSelector;
        }

        return expression ?? (freeAssetsRepo => true);
    }
}